package sp.whereru;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;


public class CourseDbAdapter {

	public static final String KEY_ROWID = "_id";
	public static final String KEY_NAME = "name";
	public static final String KEY_BUILDING = "building";
	public static final String KEY_ROOM = "room";
	public static final String KEY_START = "start";
	public static final String KEY_END = "end";
	public static final String KEY_DAYS = "days";
	public static final String KEY_ALARM = "alarm";
	public static final String KEY_ALARM_DELAY = "alarm_delay";
	private static final String TAG = "CourseDbAdapter";
	private DatabaseHelper mDbHelper;
	private SQLiteDatabase mDb;

	/**
	 * Database creation sql statement
	 */
	private static final String DATABASE_CREATE =
			"create table courses (_id integer primary key autoincrement, "
					+ "name text not null, building text not null, room text not null,"
					+		"start integer not null, end integer not null, days text not null," 
					+    		"alarm integer not null, alarm_delay integer not null);";

	public static final String SCHEDULE_DATABASE_NAME = "schedule";
	public static final String DATABASE_TABLE = "courses";
	private static final int DATABASE_VERSION = 1;

	private final Context mCtx;

	private static class DatabaseHelper extends SQLiteOpenHelper {

		DatabaseHelper(Context context) {
			super(context, SCHEDULE_DATABASE_NAME, null, DATABASE_VERSION);
		}

		@Override
		public void onCreate(SQLiteDatabase db) {
			db.execSQL(DATABASE_CREATE);
		}

		@Override
		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
			Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
					+ newVersion + ", which will destroy all old data");
			db.execSQL("DROP TABLE IF EXISTS courses");
			onCreate(db);
		}
	}


	/**
	 * Constructor - takes the context to allow the database to be
	 * opened/created
	 * 
	 * @param ctx the Context within which to work
	 */
	public CourseDbAdapter(Context context) {
		this.mCtx = context;
	}

	/**
	 * Open the course database. If it cannot be opened, try to create a new
	 * instance of the database. If it cannot be created, throw an exception to
	 * signal the failure
	 * 
	 * @return this (self reference, allowing this to be chained in an
	 *         initialization call)
	 * @throws SQLException if the database could be neither opened or created
	 */
	public CourseDbAdapter open() throws SQLException {
		mDbHelper = new DatabaseHelper(mCtx);
		mDb = mDbHelper.getWritableDatabase();
		return this;
	}

	public void close() {
		mDbHelper.close();
	}


	/**
	 * Adds a new course using the info provided. If the course is successfully 
	 * created, add it to the db and return the new rowId for that course, 
	 * otherwise return a -1 to indicate failure.
	 * 
	 * @param name 		the name of the course
	 * @param building 	the building the course is in
	 * @param room 		the room number
	 * @param start		the start time the course takes place
	 * @param end		the end time the course takes place
	 * @param days		the days the course takes place
	 * @param alarm		alarm is set or not
	 * @param alarmDelay	the alarm delay in minutes
	 * @return rowId or -1 if failed
	 */
	public long addCourse(String name, String building, String room, int start, int end, 
							String days, int alarm, int alarmDelay) {
		ContentValues initialValues = new ContentValues();
		initialValues.put(KEY_NAME, name);
		initialValues.put(KEY_BUILDING, building);
		initialValues.put(KEY_ROOM, room);
		initialValues.put(KEY_START, start);
		initialValues.put(KEY_END, end);
		initialValues.put(KEY_DAYS, days);
		initialValues.put(KEY_ALARM, alarm);
		initialValues.put(KEY_ALARM_DELAY, alarmDelay);

		return mDb.insert(DATABASE_TABLE, null, initialValues);
	}

	/**
	 * Delete the course with the given rowId
	 * 
	 * @param rowId id of course to delete
	 * @return true if deleted, false otherwise
	 */
	public boolean deleteCourse(long rowId) {
		return mDb.delete(DATABASE_TABLE, KEY_ROWID + "=" + rowId, null) > 0;
	}

	/**
	 * Return a Cursor over the list of all courses in the class schedule
	 * 
	 * @return Cursor over all courses
	 */
	public Cursor fetchAllCourses() {
		return mDb.query(DATABASE_TABLE, new String[] {KEY_ROWID, KEY_NAME,
				KEY_BUILDING, KEY_ROOM, KEY_START, KEY_END, KEY_DAYS, KEY_ALARM, KEY_ALARM_DELAY}, 
				null, null, null, null, null);
	}


	/**
	 * Return a Cursor positioned at the course that matches the given rowId
	 * 
	 * @param rowId id of course to retrieve
	 * @return Cursor positioned to matching course, if found
	 * @throws SQLException if course could not be found/retrieved
	 */
	public Cursor fetchCourse(long rowId) throws SQLException {

		Cursor mCursor =
				mDb.query(true, DATABASE_TABLE, new String[] {KEY_ROWID, KEY_NAME,
						KEY_BUILDING, KEY_ROOM, KEY_START, KEY_END, KEY_DAYS, KEY_ALARM, KEY_ALARM_DELAY}, 
						KEY_ROWID + "=" + rowId, null, null, null, null, null);
		if (mCursor != null) {
			mCursor.moveToFirst();
		}
		return mCursor;
	}

	/**
	 * Update the course using the details provided. The course to be updated is
	 * specified using the rowId, and it is altered to use the name, building,
	 * room, start, and end values passed in
	 * 
	 * @param rowId 	id of course to update
	 * @param name 		value to set course name to
	 * @param building 	value to set course building to
	 * @param room		value to set course room number to
	 * @param start		value to set course start to
	 * @param end		value to set course end to
	 * @param days		value to set the days to
	 * @param alarm		value to set alarm or not
	 * @param alarmDelay 	value to set the alarm delay
	 * @return true if the course was successfully updated, false otherwise
	 */
	public boolean updateCourse(long rowId, String name, String building, String room, 
			int start, int end, String days, int alarm, int alarmDelay) {
		ContentValues args = new ContentValues();
		args.put(KEY_NAME, name);
		args.put(KEY_BUILDING, building);
		args.put(KEY_ROOM, room);
		args.put(KEY_START, start);
		args.put(KEY_END, end);
		args.put(KEY_DAYS, days);
		args.put(KEY_ALARM, alarm);
		args.put(KEY_ALARM_DELAY, alarmDelay);

		return mDb.update(DATABASE_TABLE, args, KEY_ROWID + "=" + rowId, null) > 0;
	}

	/**
	 * Returns a Course object based on a given rowId
	 * @param rowId	the rowId of the course
	 * @return	Course object pertaining to the given rowId
	 */
	public Course returnCourse(long rowId) {
		Cursor c = fetchCourse(rowId);
		int nameColumn = c.getColumnIndex(KEY_NAME);
		int buildingColumn = c.getColumnIndex(KEY_BUILDING);
		int roomColumn = c.getColumnIndex(KEY_ROOM);
		int startColumn = c.getColumnIndex(KEY_START);
		int endColumn = c.getColumnIndex(KEY_END);
		int daysColumn = c.getColumnIndex(KEY_DAYS);
		int alarmColumn = c.getColumnIndex(KEY_ALARM);
		int alarmDelayColumn = c.getColumnIndex(KEY_ALARM_DELAY);

		return new Course(rowId, c.getString(nameColumn), c.getString(buildingColumn), 
				c.getString(roomColumn), c.getString(daysColumn),
				new SimpleTime(c.getInt(startColumn)), new SimpleTime(c.getInt(endColumn)),
				c.getInt(alarmColumn), c.getInt(alarmDelayColumn));
	}

	/**
	 * Set or cancel an alarm for a given course id
	 * @param rowId		the rowId for the course being updated
	 * @param toggle	integer either 0 to cancel alarm or 1 to set
	 * @return
	 */
	public boolean toggleAlarm(long rowId, boolean toSet, int alarmDelay) {
		int toggle;
		if(toSet)	
			toggle = 1;
		else
			toggle = 0;
		
		ContentValues args = new ContentValues();
		args.put(KEY_ALARM, toggle);
		args.put(KEY_ALARM_DELAY, alarmDelay);

		return mDb.update(DATABASE_TABLE, args, KEY_ROWID + "=" + rowId, null) > 0;
	}
	
	/**
	 * Sets the alarm delay for a given course
	 * @param rowId			the rowId of the course in the database
	 * @param alarmDelay	the alarm delay in minutes
	 * @return
	 */
	public boolean setAlarmDelay(long rowId, int alarmDelay) {		
		ContentValues args = new ContentValues();
		args.put(KEY_ALARM_DELAY, alarmDelay);

		return mDb.update(DATABASE_TABLE, args, KEY_ROWID + "=" + rowId, null) > 0;
	}
	
	/**
	 * Gets the alarm delay for a given course
	 * @param rowId
	 * @return	the alarm delay. If none, will return 0
	 */
	public int getAlarmDelay(long rowId) {
		Cursor c = fetchCourse(rowId);
		int delay = c.getInt(c.getColumnIndex(KEY_ALARM_DELAY));
		return delay;
	}
	
	/**
	 * Checks whether an alarm is set for a given course
	 * @param rowId	the rowId of the course
	 * @return
	 */
	public boolean isAlarmSet(long rowId) {
		Cursor c = fetchCourse(rowId);
		int isSet = c.getInt(c.getColumnIndex(KEY_ALARM));
		if(isSet == 0)
			return false;
		else
			return true;
	}

}
